package com.lhs.service;

import com.lhs.config.redis.ZiDeRedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Slf4j
@Service
public class CacheProtectionService {

    @Autowired
    private ZiDeRedisUtil ziDeRedisUtil;
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 防止缓存穿透：使用布隆过滤器或空值缓存[9](@ref)
     */
    public Object getDataWithPenetrationProtection(String key, Class<?> type, Supplier<?> dataLoader) {
        // 1. 从缓存获取
        Object value = ziDeRedisUtil.getCacheObject(key);
        if (value != null) {
            // 如果是空值标记，直接返回null
            if ("__NULL__".equals(value)) {
                return null;
            }
            return value;
        }

        // 2. 使用布隆过滤器检查数据是否存在（如果有）
        // 这里简化实现，实际可以使用Redisson的RBloomFilter
        // if (!bloomFilter.mightContain(key)) { return null; }

        // 3. 使用互斥锁防止缓存击穿
        String lockKey = "lock:cache:" + key;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
                // 双重检查
                value = ziDeRedisUtil.getCacheObject(key);
                if (value != null) {
                    return value;
                }

                // 从数据加载器获取数据
                value = dataLoader.get();

                if (value == null) {
                    // 缓存空值，防止穿透
                    ziDeRedisUtil.setCacheObject(key, "__NULL__", 5, TimeUnit.MINUTES);
                } else {
                    // 设置随机过期时间，防止雪崩
                    int expireTime = 3600 + new Random().nextInt(300);
                    ziDeRedisUtil.setCacheObject(key, value, expireTime, TimeUnit.SECONDS);
                }

                return value;
            } else {
                log.warn("获取缓存锁失败，key: {}", key);
                return null;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("缓存保护操作被中断", e);
            return null;
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 防止缓存雪崩：设置随机过期时间
     */
    public void setCacheWithAvalancheProtection(String key, Object value, long baseTimeout, TimeUnit unit) {
        // 在基础过期时间上增加随机偏移
        Random random = new Random();
        long timeout = unit.toSeconds(baseTimeout) + random.nextInt(300); // 随机5分钟偏移
        ziDeRedisUtil.setCacheObject(key, value, timeout, TimeUnit.SECONDS);
    }
}